package xyz.heyaoshare.core.service.system.impl;

import cn.dev33.satoken.secure.BCrypt;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.CacheableServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.heyaoshare.common.constants.CacheKey;
import xyz.heyaoshare.common.entity.bo.ResultPage;
import xyz.heyaoshare.config.satoken.utils.AuthUtils;
import xyz.heyaoshare.core.controller.system.user.vo.req.*;
import xyz.heyaoshare.core.controller.system.user.vo.resp.*;
import xyz.heyaoshare.core.entity.system.User;
import xyz.heyaoshare.core.entity.system.UserRole;
import xyz.heyaoshare.core.enums.system.user.SuperAdminEnum;
import xyz.heyaoshare.core.enums.system.user.UserGenderEnum;
import xyz.heyaoshare.core.enums.system.user.UserStatusEnum;
import xyz.heyaoshare.core.mapper.system.UserMapper;
import xyz.heyaoshare.core.mapper.system.UserRoleMapper;
import xyz.heyaoshare.core.service.system.UserService;
import xyz.heyaoshare.utils.BeanUtils;
import xyz.heyaoshare.utils.CollUtils;
import xyz.heyaoshare.utils.StrUtils;

import java.time.LocalDateTime;
import java.util.*;

import static xyz.heyaoshare.exceptions.code.ErrorInfo.*;
import static xyz.heyaoshare.exceptions.customize.ServerException.exception;

/**
 * 用户 Service 实现类
 * @author YueHe
 * @version 0.0.1
 * @since 2025/6/25 下午1:49
 */
@Slf4j
@Service
@CacheConfig(cacheNames = CacheKey.USER_SERVICE)
public class UserServiceImpl extends CacheableServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private AuthUtils authUtils;
    @Resource
    private UserRoleMapper userRoleMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insert(UserInsertReqVO reqVO) {
        // 1.校验用户名重复
        long count = QueryChain.of(mapper).eq(User::getUsername, reqVO.getUsername()).count();
        if (count > 0) throw exception(USERNAME_EXITS);

        // 2.构建用户信息
        User user = new User()
                .setNickname(reqVO.getNickname())
                .setUsername(reqVO.getUsername())
                .setPassword(BCrypt.hashpw(reqVO.getPassword(), BCrypt.gensalt()))
                .setGender(reqVO.getGender()).setRegisterTime(LocalDateTime.now())
                .setIsAdmin(SuperAdminEnum.NO.getValue())
                .setStatus(UserStatusEnum.ENABLE.getValue());

        // 3.保存用户信息
        try {
            mapper.insert(user);
        } catch (Exception e) {
            log.error("新增用户失败", e);
            throw exception(INSERT_USER_FAILED);
        }

        // 4.保存用户角色关系
        setUserRole(new UserSetRoleReqVO().setUserId(user.getId()).setRoleIds(reqVO.getRoleIds()));
        return Boolean.TRUE;
    }

    @Override
    public ResultPage<UserPageRespVO> selectPage(UserPageReqVO reqVO) {
        // 1.查询用户列表
        Page<User> userPage = QueryChain.of(mapper)
                .like(User::getNickname, reqVO.getNickname(), StrUtils.isNotBlank(reqVO.getNickname()))
                .like(User::getUsername, reqVO.getUsername(), StrUtils.isNotBlank(reqVO.getUsername()))
                .like(User::getMobile, reqVO.getMobile(), StrUtils.isNotBlank(reqVO.getMobile()))
                .ne(User::getIsAdmin, SuperAdminEnum.YES.getValue())
                .orderBy(User::getCreateTime, Boolean.FALSE)
                .page(new Page<>(reqVO.getPage(), reqVO.getSize()));

        // 2.转换为VO对象
        List<UserPageRespVO> items = Optional.ofNullable(userPage.getRecords()).orElseGet(ArrayList::new).stream().map(item -> {
            UserPageRespVO respVO = BeanUtils.copyProperties(item, UserPageRespVO.class);
            respVO.setGenderStr(UserGenderEnum.getLabel(item.getGender()));
            respVO.setStatusStr(UserStatusEnum.getLabel(item.getStatus()));
//            UserGetRoleRespVO userRole = getUserRole(new UserGetRoleReqVO().setUserId(item.getId()));
//            List<Long> roleIds = userRole.getRoleIds();
//            respVO.setRoleIds(roleIds);
            return respVO;
        }).toList();

        // 3.返回结果
        return ResultPage.result(userPage.getTotalRow(), items);
    }

    @Override
    public List<UserListRespVO> selectList(UserListReqVO reqVO) {
        // 1.查询用户列表
        List<User> userList = QueryChain.of(User.class)
                .eq(User::getStatus, UserStatusEnum.ENABLE.getValue())
                .ne(User::getIsAdmin, SuperAdminEnum.YES.getValue())
                .orderBy(User::getCreateTime, Boolean.FALSE).list();

        // 2.转换为VO对象并返回结果
        return Optional.ofNullable(userList).orElseGet(ArrayList::new).stream().map(item -> {
            UserListRespVO respVO = BeanUtils.copyProperties(item, UserListRespVO.class);
            respVO.setGenderStr(UserGenderEnum.getLabel(item.getGender()));
            return respVO;
        }).toList();
    }

    @Override
    public UserDetailRespVO selectDetail(UserDetailReqVO reqVO) {
        User user = getById(reqVO.getUserId());
        if (user == null) throw exception(USER_NOT_EXIST);

        UserDetailRespVO respVO = BeanUtils.copyProperties(user, UserDetailRespVO.class);
        respVO.setGenderStr(UserGenderEnum.getLabel(user.getGender()));

        UserGetRoleRespVO userRole = getUserRole(new UserGetRoleReqVO().setUserId(user.getId()));
        List<Long> roleIds = userRole.getRoleIds();
        respVO.setRoleIds(roleIds);
        return respVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(UserDeleteReqVO reqVO) {
        // 1.做一系列操作前校验
        for (Long userId : reqVO.getUserIds()) {
            // 这里做各种校验....
        }

        // 2.删除用户信息
        try {
            // 2.1 删除用户信息
            UpdateChain.of(mapper).in(User::getId, reqVO.getUserIds()).remove();
            // 2.2 删除用户角色关系
            UpdateChain.of(UserRole.class).in(UserRole::getUserId, reqVO.getUserIds()).remove();
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("删除用户信息失败", e);
            throw exception(DELETE_USER_FAILED);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateData(UserUpdateReqVO reqVO) {
        // 1.设置用户信息
        try {
            UpdateChain.of(mapper)
                    .set(User::getNickname, reqVO.getNickname())
                    .set(User::getGender, reqVO.getGender())
                    .set(User::getEmail, reqVO.getEmail())
                    .set(User::getMobile, reqVO.getMobile())
                    .eq(User::getId, reqVO.getId()).update();
        } catch (Exception e) {
            log.error("更新用户信息失败", e);
            throw exception(UPDATE_USER_FAILED);
        }

        // 2.设置用户角色信息
        setUserRole(new UserSetRoleReqVO().setUserId(reqVO.getId()).setRoleIds(reqVO.getRoleIds()));
        return Boolean.TRUE;
    }

    @Override
    public UserInfoRespVO getUserInfo() {
        // 1. 获取登录用户信息
        User loginUser = authUtils.getUser();

        // 2.获取用户角色信息
        UserGetRoleRespVO userRole = getUserRole(new UserGetRoleReqVO().setUserId(loginUser.getId()));

        // 3.返回结果
        return new UserInfoRespVO()
                .setAvatar(loginUser.getAvatar())
                .setRoleIds(userRole.getRoleIds())
                .setUserId(loginUser.getId())
                .setNickname(loginUser.getNickname())
                .setUsername(loginUser.getUsername())
                .setStatus(loginUser.getStatus());
    }

    @Override
    public Set<String> getPermissions() {
        // 1.获取当前登录用户
        User user = authUtils.getUser();

        // 2.如果是超管，则返回所有权限
        if (user.getIsAdmin() == SuperAdminEnum.YES.getValue()) {
            return mapper.selectPermissionsAll();
        }
        // 3.如果不是超管，则返回当前用户的权限
        if (user.getIsAdmin() == SuperAdminEnum.NO.getValue()) {
            return mapper.selectPermissions(user.getId());
        }

        return new HashSet<>();
    }

    /**
     * 设置用户角色
     * <p>
     * 方法步骤如下：
     * 1. 获取原始的角色列表：通过用户ID查询当前用户的所有角色信息。
     * 2. 获取需要新增和删除的Id列表：将请求中的角色ID列表与原始角色ID列表进行比较，找出需要新增和删除的角色ID。
     * 3. 执行新增处理：如果有需要新增的角色ID，则创建新的UserRole对象并插入到数据库中。
     * 4. 执行删除处理：如果有需要删除的角色ID，则从数据库中删除对应的UserRole记录。
     * <p>
     * 如果在新增或删除过程中发生异常，将记录错误日志并抛出异常。
     *
     * @param reqVO 请求体对象，包含用户ID和角色ID列表
     */
    private void setUserRole(UserSetRoleReqVO reqVO) {
        // 1.获取原始的角色列表
        List<UserRole> list = QueryChain.of(UserRole.class).eq(UserRole::getUserId, reqVO.getUserId()).select(UserRole::getRoleId).list();
        List<Long> roleIds = Optional.ofNullable(list).orElseGet(ArrayList::new).stream().map(UserRole::getRoleId).filter(Objects::nonNull).toList();

        // 2.获取需要新增和删除的Id列表
        List<Long> insertIds = CollUtils.subtractToList(reqVO.getRoleIds(), roleIds);
        List<Long> deleteIds = CollUtils.subtractToList(roleIds, reqVO.getRoleIds());

        // 3.执行新增处理
        if (CollUtils.isNotEmpty(insertIds)) {
            List<UserRole> insertList = new ArrayList<>();
            for (Long roleId : insertIds) {
                UserRole userRole = new UserRole().setUserId(reqVO.getUserId()).setRoleId(roleId);
                insertList.add(userRole);
            }
            if (CollUtils.isNotEmpty(insertList)) {
                try {
                    userRoleMapper.insertBatch(insertList);
                } catch (Exception e) {
                    log.error("新增用户角色失败", e);
                    throw exception(INSERT_USER_ROLE_FAILED);
                }
            }
        }

        // 4.执行新增处理
        if (CollUtils.isNotEmpty(deleteIds)) {
            try {
                UpdateChain.of(UserRole.class).eq(UserRole::getUserId, reqVO.getUserId()).in(UserRole::getRoleId, deleteIds).remove();
            } catch (Exception e) {
                log.error("删除用户角色失败", e);
                throw exception(DELETE_USER_ROLE_FAILED);
            }
        }
    }

    /**
     * 获取用户角色信息
     * 方法描述：
     * 此方法用于根据用户ID获取用户的角色信息。
     * 1. 使用QueryChain通过userRoleMapper查询用户ID对应的所有UserRole记录，并仅选择roleId字段。
     * 2. 如果查询结果为null，则创建一个空的ArrayList；否则，将查询结果转换为stream，提取UserRole对象的roleId字段，并过滤掉null值，最终转换为List<Long>类型。
     * 3. 创建一个UserGetRoleRespVO对象，设置用户ID和角色ID列表，并返回该对象。
     *
     * @param reqVO 请求对象，包含用户ID
     * @return UserGetRoleRespVO 对象，包含用户ID和角色ID列表
     */
    private UserGetRoleRespVO getUserRole(UserGetRoleReqVO reqVO) {
        List<UserRole> list = QueryChain.of(userRoleMapper).eq(UserRole::getUserId, reqVO.getUserId()).select(UserRole::getRoleId).list();
        List<Long> roleIds = Optional.ofNullable(list).orElseGet(ArrayList::new).stream().map(UserRole::getRoleId)
                .filter(Objects::nonNull)
                .distinct()
                .toList();

        return new UserGetRoleRespVO().setUserId(reqVO.getUserId()).setRoleIds(roleIds);
    }

}